package main

import (
	"encoding/json"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"github.com/gocolly/colly/v2"
	"github.com/gocolly/colly/v2/extensions"
	"github.com/labstack/gommon/log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strconv"
	"strings"
)

const (
	BaiDu = iota
	WeiBo
	TouTiao
	ZhiHu
	Last
)

// HotSearchDto 搜索结果项
type HotSearchDto struct {
	Sort  int    `json:"sort"`
	Title string `json:"title"`
	Desc  string `json:"desc"`
	Url   string `json:"url"`
	Hot   string `json:"hot"`
}

// IHotSearch 热搜接口
type IHotSearch interface {
	BindHTMLSelector()
	Visit() []HotSearchDto
}

// BaseSearch 基础搜索服务 实现接口的三个方法
type BaseSearch struct {
	Url       string
	Collector *colly.Collector
	Data      []HotSearchDto
	Limit     int
}

//func (bs *BaseSearch) Ajax() {
//	fmt.Println("base ajax")
//	bs.Data = []HotSearchDto{}
//}

func (bs *BaseSearch) BindHTMLSelector() {
	fmt.Println("Nothing to do")
}

func (bs *BaseSearch) Visit() []HotSearchDto {
	bs.Data = []HotSearchDto{}
	err := bs.Collector.Visit(bs.Url)
	if err != nil {
		fmt.Printf("%v\n", err)
		return []HotSearchDto{}
	}

	return bs.Data
}

// HotSearchRouter 路由选择器
type HotSearchRouter struct {
	Router map[int]IHotSearch
}

func (r *HotSearchRouter) newCollector() *colly.Collector {
	return colly.NewCollector(
		colly.IgnoreRobotsTxt(),
		colly.AllowURLRevisit(),
		func(collector *colly.Collector) {
			// 设置随机ua
			extensions.RandomUserAgent(collector)
			// 设置cookiejar
			cjar, err := cookiejar.New(nil)
			if err == nil {
				collector.SetCookieJar(cjar)
			}
		})
}

func (r *HotSearchRouter) Init() {
	r.Router = make(map[int]IHotSearch)
	r.Router[BaiDu] = &BaiDuHotSearch{BaseSearch{
		Url:       "https://top.baidu.com/board?tab=realtime",
		Collector: r.newCollector(),
	}}
	r.Router[BaiDu].BindHTMLSelector()

	r.Router[WeiBo] = &WeiBoHotSearch{BaseSearch{
		Url:       "https://weibo.com/ajax/side/hotSearch",
		Collector: r.newCollector(),
	}}
	r.Router[WeiBo].BindHTMLSelector()

	r.Router[TouTiao] = &TouTiaoHotSearch{BaseSearch{
		Url:       "https://www.toutiao.com/hot-event/hot-board/?origin=toutiao_pc",
		Collector: r.newCollector(),
	}}
	r.Router[TouTiao].BindHTMLSelector()

	r.Router[ZhiHu] = &ZhiHuHotSearch{BaseSearch{
		Url:       "https://tophub.today/n/mproPpoq6O",
		Collector: r.newCollector(),
	}}
	r.Router[ZhiHu].BindHTMLSelector()
}

func (r *HotSearchRouter) Route(key int) IHotSearch {
	return r.Router[key]
}

// BaiDuHotSearch 百度
type BaiDuHotSearch struct {
	BaseSearch
}

func (hs *BaiDuHotSearch) BindHTMLSelector() {
	hs.Collector.OnHTML(".container-bg_lQ801", func(element *colly.HTMLElement) {
		element.DOM.Find(".category-wrap_iQLoo").Each(func(index int, itemSelection *goquery.Selection) {
			contentSelection := itemSelection.ChildrenFiltered(".content_1YWBm")
			title := contentSelection.Find(".c-single-text-ellipsis").Text()
			href, _ := contentSelection.ChildrenFiltered("a").Attr("href")
			desc := contentSelection.Find(".hot-desc_1m_jR").First().Text()
			if len(desc) > 0 {
				desc = strings.ReplaceAll(desc, "查看更多>", "")
			}
			hot := itemSelection.Find(".trend_2RttY .hot-index_1Bl1a").Text()
			hs.Data = append(hs.Data, HotSearchDto{
				Sort:  index,
				Title: title,
				Url:   href,
				Desc:  desc,
				Hot:   hot,
			})
		})
	})
}

// WeiBoHotSearch 微博
type WeiBoHotSearch struct {
	BaseSearch
}

// BindHTMLSelector 微博 重写父类ajax获取数据
func (hs *WeiBoHotSearch) BindHTMLSelector() {
	hs.Collector.OnResponse(func(response *colly.Response) {
		if response.StatusCode == http.StatusOK {
			var tempMap = make(map[string]interface{})
			err := json.Unmarshal(response.Body, &tempMap)
			if err != nil {
				log.Errorf("json反序列化失败:%v", err)
			}
			realtimeArr := tempMap["data"].(map[string]interface{})["realtime"].([]interface{})
			for i, v := range realtimeArr {
				word := v.(map[string]interface{})["word"].(string)
				wordScheme := word
				wsi := v.(map[string]interface{})["word_scheme"]
				if wsi != nil {
					wordScheme = wsi.(string)
				}
				ci := v.(map[string]interface{})["category"]
				category := "分类"
				if ci != nil {
					category = ci.(string)
				}

				hot := v.(map[string]interface{})["num"].(float64)
				hs.Data = append(hs.Data, HotSearchDto{
					Sort:  i,
					Title: word,
					Url:   "https://s.weibo.com/weibo?q=" + url.QueryEscape(wordScheme),
					Desc:  fmt.Sprintf("%s: %s", category, word),
					Hot:   strconv.Itoa(int(hot)),
				})
			}
			return
		}
		log.Errorf("读取微博ajax接口失败:%s", string(response.Body))
	})
}

// 头条
type TouTiaoHotSearch struct {
	BaseSearch
}

func (hs *TouTiaoHotSearch) BindHTMLSelector() {
	hs.Collector.OnResponse(func(response *colly.Response) {
		if response.StatusCode == http.StatusOK {
			var tempMap = make(map[string]interface{})
			err := json.Unmarshal(response.Body, &tempMap)
			if err != nil {
				log.Errorf("json反序列化失败:%v", err)
			}
			dataArr := tempMap["data"].([]interface{})
			for i, v := range dataArr {
				title := v.(map[string]interface{})["Title"].(string)
				link := v.(map[string]interface{})["Url"].(string)
				hot := v.(map[string]interface{})["HotValue"].(string)
				labelInter := v.(map[string]interface{})["LabelDesc"]
				desc := title
				if labelInter != nil {
					desc = labelInter.(string) + ":" + desc
				}
				hs.Data = append(hs.Data, HotSearchDto{
					Sort:  i,
					Title: title,
					Url:   link,
					Desc:  desc,
					Hot:   hot,
				})
			}
			return
		}
		log.Errorf("读取头条ajax接口失败:%s", string(response.Body))
	})
}

// 知乎
type ZhiHuHotSearch struct {
	BaseSearch
}

func (hs *ZhiHuHotSearch) BindHTMLSelector() {
	hs.Collector.OnHTML(".Zd-p-Sc", func(element *colly.HTMLElement) {
		element.DOM.Find(".cc-dc-c tbody").First().Find("tr").Each(func(i int, selection *goquery.Selection) {
			title := selection.Find(".al a").Text()
			href, _ := selection.Find(".al a").Attr("href")
			hot := selection.Find("td:nth-child(3)").Text()
			hs.Data = append(hs.Data, HotSearchDto{
				Sort:  i,
				Title: title,
				Url:   element.Request.AbsoluteURL(href),
				Desc:  title,
				Hot:   hot,
			})
		})
	})
}
